package edu.indiana.d2i.util;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;

public class Utilities {
	public static void downloadFile(Resource resource, String tofile) {
		try {
			BufferedOutputStream bos = new BufferedOutputStream(
					new FileOutputStream(new File(tofile)));
			bos.write((byte[]) resource.getContent());
			bos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (RegistryException e) {
			e.printStackTrace();
		}
	}

	@SuppressWarnings("rawtypes")
	public static void unJar(File jarFile, File toDir) throws IOException {
		JarFile jar = new JarFile(jarFile);
		try {
			Enumeration entries = jar.entries();
			while (entries.hasMoreElements()) {
				JarEntry entry = (JarEntry) entries.nextElement();
				if (!entry.isDirectory()) {
					InputStream in = jar.getInputStream(entry);
					try {
						File file = new File(toDir, entry.getName());
						if (!file.getParentFile().mkdirs()) {
							if (!file.getParentFile().isDirectory()) {
								throw new IOException(
										"Mkdirs failed to create "
												+ file.getParentFile()
														.toString());
							}
						}
						OutputStream out = new FileOutputStream(file);
						try {
							byte[] buffer = new byte[8192];
							int i;
							while ((i = in.read(buffer)) != -1) {
								out.write(buffer, 0, i);
							}
						} finally {
							out.close();
						}
					} finally {
						in.close();
					}
				}
			}
		} finally {
			jar.close();
		}
	}
	
	/**  
	 * jarFileName -- the name of the jar file
	 * classname   -- the name of main class
	 */
	@SuppressWarnings("deprecation")
	public static Class<?> generateClassFromJarFile(String jarFileName, String classname) throws IOException, ClassNotFoundException {
		final String TMP_DIR = "./tmp/";

		// open the jar file
		String fileName = jarFileName;
		File file = new File(fileName);
		String mainClassName = null;
		JarFile jarFile = null;
		try {
			jarFile = new JarFile(fileName);
		} catch (IOException io) {
			io.printStackTrace();
		}

		// get the main class from the manifest
		Manifest manifest = jarFile.getManifest();
		if (manifest != null) {
			mainClassName = manifest.getMainAttributes().getValue("Main-Class");
		}
		jarFile.close();
//		mainClassName = "edu.indiana.d2i.app.SimpleScript";
		if (mainClassName == null) {
			if (classname == null) {
				System.err.println("mainClassName is missing");
				System.exit(-1);
			}
			mainClassName = classname;
		}
		mainClassName = mainClassName.replaceAll("/", ".");

		// extract the jar file to a temporary folder
		File tmpDir = new File(TMP_DIR);
		if (!tmpDir.exists()) {
			if (!tmpDir.mkdir()) {
				System.err.println("Mkdirs failed to create " + tmpDir);
				System.exit(-1);
			}
		}
		final File workDir = File.createTempFile("htrc-unjar", "", tmpDir);
		workDir.delete();
		workDir.mkdirs();
		if (!workDir.isDirectory()) {
			System.err.println("Mkdirs failed to create " + workDir);
			System.exit(-1);
		}
		Utilities.unJar(file, workDir);

		// set the classpath for class loader
		ArrayList<URL> classPath = new ArrayList<URL>();
		classPath.add(new File(workDir + "/").toURL());
		classPath.add(file.toURL());
		classPath.add(new File(workDir, "classes/").toURL());
		classPath.add(new File(workDir, "edu/").toURL());
		File[] libs = new File(workDir, "lib").listFiles();
		if (libs != null) {
			for (int i = 0; i < libs.length; i++) {
				classPath.add(libs[i].toURL());
			}
		}

		// load the class from the workDir
		ClassLoader loader = new URLClassLoader(classPath.toArray(new URL[0]));
		Thread.currentThread().setContextClassLoader(loader);
		Class<?> mainClass = Class.forName(mainClassName, true, loader);
		
		return mainClass;
	}
}
